// SPDX-License-Identifier: Mulan PSL v2
/*
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * This software is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

use std::{any, fmt::Debug, marker::PhantomData, mem, os::raw::c_void, ptr, slice};

use bitflags::bitflags;

use super::SerializeError;

bitflags! {
    #[repr(C)]
    #[derive(Debug, Clone, PartialEq, Eq)]
    pub struct ArgumentFlag: u32 {
        const ARG_IN = 0b0001;
        const ARG_OUT = 0b0010;
        const ARG_VIRT = 0b0100;
    }
}

#[repr(C)]
#[derive(Debug, Clone)]
pub struct Argument<'a> {
    pub(crate) ptr: *const c_void,
    pub(crate) align: usize,
    pub(crate) size: usize,
    pub(crate) count: usize,
    pub(crate) flag: ArgumentFlag,
    pub(crate) marker: PhantomData<&'a ()>,
}

impl<'a> Argument<'a> {
    pub fn with_value<T>(value: &'a T, flag: ArgumentFlag) -> Self {
        let size = mem::size_of::<T>();
        let align = mem::align_of::<T>();
        let count = 1;

        let ptr = if size == 0 {
            ptr::null()
        } else {
            ptr::from_ref(value).cast::<c_void>()
        };

        Self {
            ptr,
            size,
            align,
            count,
            flag,
            marker: PhantomData,
        }
    }

    pub fn with_slice<T>(value: &'a [T], flag: ArgumentFlag) -> Self {
        let size = mem::size_of_val(value);
        let align = mem::align_of::<T>();
        let count = value.len();

        let ptr = if size == 0 {
            ptr::null()
        } else {
            value.as_ptr().cast::<c_void>()
        };

        Self {
            ptr,
            size,
            align,
            count,
            flag,
            marker: PhantomData,
        }
    }

    pub fn get_value<T>(&self) -> Result<&T, SerializeError> {
        if self.size != mem::size_of::<T>() {
            return Err(SerializeError::SizeMismatch {
                expected: mem::size_of::<T>(),
                actual: self.align,
            });
        }

        if self.align != mem::align_of::<T>() {
            return Err(SerializeError::AlignmentMismatch {
                expected: mem::align_of::<T>(),
                actual: self.align,
            });
        }

        if mem::size_of::<T>() == 0 {
            return Ok(unsafe { &*std::ptr::NonNull::<T>::dangling().as_ptr() });
        }

        if self.ptr.is_null() {
            return Err(SerializeError::NullPointer);
        }

        let value_ptr = self.ptr.cast::<T>();
        if !value_ptr.is_aligned() {
            return Err(SerializeError::UnalignedAccess {
                type_name: any::type_name::<T>(),
                alignment: mem::align_of::<T>(),
            });
        }

        Ok(unsafe { &*value_ptr })
    }

    /// 获取指针（为recorder模块支持）
    pub fn ptr(&self) -> *const c_void {
        self.ptr
    }

    /// 获取大小（为recorder模块支持）
    pub fn size(&self) -> usize {
        self.size
    }

    /// 获取对齐（为recorder模块支持）
    pub fn align(&self) -> usize {
        self.align
    }

    /// 获取标志（为recorder模块支持）
    pub fn flag(&self) -> ArgumentFlag {
        self.flag
    }

    /// 从原始部件创建参数（不安全）
    pub unsafe fn from_raw_parts(
        ptr: *const c_void,
        size: usize,
        align: usize,
        count: usize,
        flag: ArgumentFlag,
    ) -> Self {
        Self {
            ptr,
            size,
            align,
            count,
            flag,
            marker: PhantomData,
        }
    }
}

impl Argument<'_> {
    pub const fn type_size() -> usize {
        mem::size_of::<Self>()
    }

    pub const fn type_align() -> usize {
        mem::align_of::<Self>()
    }

    pub fn serialized_align(&self) -> usize {
        Self::type_align().max(self.align)
    }

    pub fn serialized_padding(&self) -> usize {
        let align = self.serialized_align();
        (align - (Self::type_size() % align)) % align
    }

    pub fn serialized_size(&self) -> usize {
        Self::type_size()
            .checked_add(self.serialized_padding())
            .and_then(|v| v.checked_add(self.size))
            .expect("Serialized size overflow")
    }

    pub fn serialize_into(&self, buff: &mut [u8]) -> Result<usize, SerializeError> {
        let header_ptr = ptr::from_ref(self).cast::<u8>();
        let header_size = Self::type_size();

        // Check buffer capacity
        let total_size = self.serialized_size();
        let buffer_capacity = buff.len();
        if buffer_capacity < total_size {
            return Err(SerializeError::InsufficientBuffer {
                required: total_size,
                capacity: buffer_capacity,
            });
        }

        // Check header alignment
        if !buff.as_ptr().cast::<Self>().is_aligned() {
            return Err(SerializeError::UnalignedAccess {
                type_name: any::type_name::<Self>(),
                alignment: Self::type_align(),
            });
        }

        // Write header bytes
        let header_bytes = unsafe { slice::from_raw_parts(header_ptr, header_size) };
        buff[..header_size].copy_from_slice(header_bytes);

        // Write padding bytes
        let padding_size = self.serialized_padding();
        if padding_size > 0 {
            let padding_start = header_size;
            let padding_end = header_size
                .checked_add(padding_size)
                .ok_or(SerializeError::SizeOverflow)?;

            buff[padding_start..padding_end].fill(0);
        }

        // Write data bytes
        if !self.ptr.is_null() || self.size > 0 {
            let data_bytes = unsafe { slice::from_raw_parts(self.ptr.cast::<u8>(), self.size) };
            let data_start = header_size + padding_size;
            let data_end = data_start + self.size;

            buff[data_start..data_end].copy_from_slice(data_bytes);
        }

        Ok(total_size)
    }

    pub fn deserialize_from(buff: &[u8]) -> Result<(usize, Self), SerializeError> {
        let header_ptr = buff.as_ptr().cast::<Self>();
        let header_size = Self::type_size();

        // Check buffer capacity
        let buffer_capacity = buff.len();
        if buffer_capacity < header_size {
            return Err(SerializeError::InsufficientBuffer {
                required: header_size,
                capacity: buffer_capacity,
            });
        }

        // Check header alignment
        if !header_ptr.is_aligned() {
            return Err(SerializeError::UnalignedAccess {
                type_name: any::type_name::<Self>(),
                alignment: Self::type_align(),
            });
        }

        // Parse argument
        let mut argument = unsafe { ptr::read(header_ptr) };
        let data_start = header_size
            .checked_add(argument.serialized_padding())
            .ok_or(SerializeError::SizeOverflow)?;
        let data_end = data_start
            .checked_add(argument.size)
            .ok_or(SerializeError::SizeOverflow)?;

        // Check data size
        if buffer_capacity < data_end {
            return Err(SerializeError::InsufficientBuffer {
                required: data_end,
                capacity: buffer_capacity,
            });
        }

        // Update data pointer
        if argument.size == 0 {
            argument.ptr = ptr::null();
        } else {
            argument.ptr = unsafe { buff.as_ptr().add(data_start).cast::<c_void>() };
        }
        argument.marker = PhantomData;

        Ok((data_end, argument))
    }
}
